﻿using Heroius.Extension;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace PicRowScaler
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = Plan;
        }

        public ScalerPlan Plan { get; set; } = new ScalerPlan();

        string[] ValidExt = { ".JPG", ".BMP", ".PNG", ".JPEG" };

        private void Grid_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                // Note that you can have more than one file.
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

                foreach (var f in files)
                {
                    if (ValidExt.Contains(new FileInfo(f).Extension.ToUpper()))
                    {
                        Plan.Files.Add(new ScalerPlanImageItem() { File = f });
                    }
                }
            }
        }

        private void Calc_Click(object sender, RoutedEventArgs e)
        {
            int n = Plan.Files.Count;
            //获取图像高宽比
            double[] factor = new double[n];
            for (int i = 0; i < n; i++)
            {
                var f = Plan.Files[i];
                factor[i] = GetImageHWRatio(f);
            }
            //构建系数矩阵
            double[,] a = new double[n, n];
            double[] b = new double[n];
            for (int i = 0; i < n; i++)
            {
                a[0, i] = 1;
            }
            b[0] = Plan.TotalScale;
            for (int i = 1; i < n; i++)
            {
                a[i, 0] = factor[0];
                a[i, i] = -factor[i];
            }
            //执行计算
            if (Gaus(a, b, n))
            {
                int k = 1;
                TbResult.Text = b.Select(d => $"X{k++} : {d.ToString()}").Merge("\r\n");
            }
        }

        /// <summary>
        /// 从图片中获取像素高宽比
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        double GetImageHWRatio(ScalerPlanImageItem item)
        {
            var frame = BitmapDecoder.Create(new Uri(item.File), BitmapCreateOptions.None, BitmapCacheOption.OnDemand).Frames[0];
            return frame.PixelHeight.As<double>() / frame.PixelWidth.As<double>();
        }
        /// <summary>
        /// 执行全选主元Gauss消去法求解线性方程组
        /// </summary>
        /// <param name="a">系数矩阵</param>
        /// <param name="b">输入：常数向量；输出：解向量</param>
        /// <param name="n">阶</param>
        /// <returns></returns>
        bool Gaus(double[,] a, double[] b, int n)
        {
            int[] js;
            int l, k, i, j, s = 0;
            double d, t;
            js = new int[n];
            l = 1;
            for (k = 0; k <= n - 2; k++)
            {
                d = 0.0;
                for (i = k; i <= n - 1; i++)
                    for (j = k; j <= n - 1; j++)
                    {
                        t = Math.Abs(a[i, j]);
                        if (t > d) { d = t; js[k] = j; s = i; }
                    }
                if (d + 1.0 == 1.0) l = 0;
                else
                {
                    if (js[k] != k)
                        for (i = 0; i <= n - 1; i++)
                        {
                            t = a[i, k];
                            a[i, k] = a[i, js[k]];
                            a[i, js[k]] = t;
                        }
                    if (s != k)
                    {
                        for (j = k; j <= n - 1; j++)
                        {
                            t = a[k, j];
                            a[k, j] = a[s, j];
                            a[s, j] = t;
                        }
                        t = b[k]; b[k] = b[s]; b[s] = t;
                    }
                }
                if (l == 0)
                {
                    return false;
                }
                d = a[k, k];
                for (j = k + 1; j <= n - 1; j++)
                    a[k, j] = a[k, j] / d;
                b[k] = b[k] / d;
                for (i = k + 1; i <= n - 1; i++)
                {
                    for (j = k + 1; j <= n - 1; j++)
                        a[i, j] = a[i, j] - a[i, k] * a[k, j];
                    b[i] = b[i] - a[i, k] * b[k];
                }
            }
            d = a[n - 1, n - 1];
            if (Math.Abs(d) + 1.0 == 1.0)
            {
                return false;
            }
            b[n - 1] = b[n - 1] / d;
            for (i = n - 2; i >= 0; i--)
            {
                t = 0.0;
                for (j = i + 1; j <= n - 1; j++)
                    t = t + a[i, j] * b[j];
                b[i] = b[i] - t;
            }
            js[n - 1] = n - 1;
            for (k = n - 1; k >= 0; k--)
                if (js[k] != k)
                {
                    t = b[k]; b[k] = b[js[k]]; b[js[k]] = t;
                }
            return true;
        }

        private void Help_Click(object sender, RoutedEventArgs e)
        {
            Process.Start("https://heroius.com/blog/?p=297");
        }
    }
}
